package cn.kkcxy.blog.system.service.impl;

import cn.kkcxy.blog.common.constant.ExceptionMessageConstant;
import cn.kkcxy.blog.core.convert.AdministratorInfoConverter;
import cn.kkcxy.blog.core.dto.client.LoginParamsDTO;
import cn.kkcxy.blog.core.entity.sys.SysPermission;
import cn.kkcxy.blog.core.entity.sys.SysUser;
import cn.kkcxy.blog.core.enums.LoginTypeEnum;
import cn.kkcxy.blog.core.exception.auth.NotFoundLoginTypeHandlerException;
import cn.kkcxy.blog.core.result.ResponseEntity;
import cn.kkcxy.blog.core.vo.LoginVO;
import cn.kkcxy.blog.core.vo.admin.AdministratorInfoVO;
import cn.kkcxy.blog.core.vo.admin.MetaVO;
import cn.kkcxy.blog.core.vo.admin.RouterVO;
import cn.kkcxy.blog.core.vo.admin.SimpleInfoVO;
import cn.kkcxy.blog.system.factory.login.LoginTypeHandler;
import cn.kkcxy.blog.system.factory.login.LoginTypeHandlerFactory;
import cn.kkcxy.blog.system.service.AuthService;
import cn.kkcxy.blog.system.service.sys.SysPermissionService;
import cn.kkcxy.blog.system.service.sys.SysRoleService;
import cn.kkcxy.blog.system.service.sys.SysUserService;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @BelongsProject: kkcxy-blog
 * @BelongsPackage: cn.kkcxy.blog.system.service.impl
 * @Author: kkcxy
 * @CreateTime: 2024-09-11 22:41
 * @Description: 认证服务实现
 * @Version: 1.0
 */
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    /**
     * 注入登录类型处理器工厂
     */
    @Resource
    private LoginTypeHandlerFactory loginTypeHandlerFactory;

    /**
     * sys user service
     */
    @Resource
    private SysUserService sysUserService;

    /**
     * sys role service
     */
    @Resource
    private SysRoleService sysRoleService;

    /**
     * sys permission service
     */
    @Resource
    private SysPermissionService sysPermissionService;

    /**
     * Commmon ThreadPool
     */
    @Resource
    private ThreadPoolExecutor commonThreadPool;

    /**
     * @description: 用户登录
     * @author: kkcxy
     * @date: 2024/9/11 23:55
     * @param: [code, loginType, loginParamsDTO, ip]
     * @return: ResponseEntity<SaTokenInfo>
     **/
    @Override
    @SneakyThrows
    public ResponseEntity<LoginVO> login(String code, Integer loginType, LoginParamsDTO loginParamsDTO, String ip) {
        // 未找到登录类型处理器
        if (loginType == null || Objects.isNull(LoginTypeEnum.getType(loginType))) {
            throw new NotFoundLoginTypeHandlerException(ExceptionMessageConstant.LOGIN_TYPE_NOT_FOUND);
        }

        // 得到对应登录类型的处理器
        LoginTypeHandler handler = loginTypeHandlerFactory.getHandlerByLoginType(loginType);
        // 未找到对应处理器
        if (Objects.isNull(handler)) {
            throw new NotFoundLoginTypeHandlerException(ExceptionMessageConstant.LOGIN_TYPE_NOT_FOUND);
        }
        // 得到登录处理的结果
        Map<String, String> result = handler.login(code, loginParamsDTO, ip);

        LoginVO vo = new LoginVO();
        vo.setToken(result.get("token"));

        CompletableFuture<List<String>> getRoles = CompletableFuture.supplyAsync(() -> this.getRoleList(Long.parseLong(result.get("userId"))), commonThreadPool);

        CompletableFuture<List<String>> getPermissions = CompletableFuture.supplyAsync(() -> this.getPermissionList(Long.parseLong(result.get("userId"))), commonThreadPool);

        CompletableFuture.allOf(getRoles, getPermissions).join();

        vo.setRoles(getRoles.get());
        vo.setPermissions(getPermissions.get());

        return ResponseEntity.success(vo);
    }

    /**
     * @description: 获取权限列表
     * @author: kkcxy
     * @date: 2024/10/7 21:15
     * @param: [userId]
     * @return: java.util.List<java.lang.String>
     **/
    @Override
    public List<String> getPermissionList(Long userId) {
        return sysPermissionService.getPermissionList(userId);
    }

    /**
     * @description: 获取角色列表
     * @author: kkcxy
     * @date: 2024/10/7 21:15
     * @param: [userId]
     * @return: java.util.List<java.lang.String>
     **/
    @Override
    public List<String> getRoleList(Long userId) {
        return sysRoleService.getRoleList(userId);
    }

    /**
     * @description: 获取路由列表
     * @author: kkcxy
     * @date: 2024/10/8 0:26
     * @param: [userId]
     * @return: java.util.List<cn.kkcxy.blog.core.vo.admin.RouterVO>
     **/
    @Override
    public List<RouterVO> getAdminRouters(Long userId) {
        // 查询角色对应的路由
        List<Long> routerIds = sysPermissionService.getRouterIdsByUserId(userId);
        // 获取基础路由
        List<SysPermission> baseRouterList = sysPermissionService.getRouterList(routerIds);
        // 构建结果集
        List<RouterVO> routerList = getSubRouterList(0L, baseRouterList);
        return routerList.stream().sorted(Comparator.comparingInt(RouterVO::getSort)).collect(Collectors.toList());
    }

    private List<RouterVO> getSubRouterList(Long parentId, List<SysPermission> routerList) {
        List<RouterVO> routerVo = new LinkedList<>();
        for (SysPermission permission : routerList) {
            if (Objects.equals(permission.getParentId(), parentId)) {
                RouterVO routerVO = new RouterVO();
                routerVO.setName(permission.getName());
                routerVO.setComponent(permission.getComponent());
                routerVO.setPath(permission.getPath());
                routerVO.setSort(permission.getSort());
                routerVO.setHidden(permission.getHidden());
                routerVO.setMeta(new MetaVO(permission.getTitle(), permission.getIcon()));
                routerVO.setChildren(getSubRouterList(permission.getId(), routerList));
                routerVo.add(routerVO);
            }
        }
        return routerVo;
    }

    /**
     * @description: 获取管理员信息
     * @author: kkcxy
     * @date: 2024/10/29 1:09
     * @param: [adminId]
     * @return: cn.kkcxy.blog.core.vo.admin.AdministratorInfoVO
     **/
    @Override
    public AdministratorInfoVO getAdministratorInfo(Long adminId) {
        // 构建结果集
        AdministratorInfoVO info = new AdministratorInfoVO();
        // 获取管理员基本信息
        SysUser user = sysUserService.getById(adminId);
        // 转换管理员基本信息
        SimpleInfoVO simpleInfoVO = AdministratorInfoConverter.INSTANCE.convertAdministratorInfoTOSimpleInfo(user);
        // 得到管理员角色名称
        String roleName = sysRoleService.getRoleNameByAdministratorId(adminId);
        simpleInfoVO.setRoleName(roleName);
        info.setSimpleInfo(simpleInfoVO);
        return info;
    }

}
